home *** CD-ROM | disk | FTP | other *** search
/ PC Media 7 / PC MEDIA CD07.iso / share / prog / cm / cmtbintr.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-06  |  10.6 KB  |  416 lines

  1. // CmTBinTr.cc
  2. // -----------------------------------------------------------------
  3. // Compendium - C++ Container Class Library
  4. // Copyright (C) 1992-1994, Glenn M. Poorman, All rights reserved
  5. // -----------------------------------------------------------------
  6. // Binary tree template implementation.
  7. // -----------------------------------------------------------------
  8.  
  9.  
  10. // "CmTBinaryTree" is the default tree constructor.
  11. //
  12. template <class T> CmTBinaryTree<T>::CmTBinaryTree()
  13.                                    : _root(NULL)
  14. {}
  15.  
  16.  
  17. // "CmTBinaryTree" is the tree copy constructor.
  18. //
  19. template <class T> CmTBinaryTree<T>::CmTBinaryTree(const CmTBinaryTree<T>& tr)
  20.                                    : CmTContainer<T>(tr)
  21. {
  22.   _root = NULL;
  23.   copy   (tr);
  24.   balance();
  25. }
  26.  
  27.  
  28. // "~CmTBinaryTree" is the tree destructor.
  29. //
  30. template <class T> CmTBinaryTree<T>::~CmTBinaryTree()
  31. {
  32.   removeAll();
  33. }
  34.  
  35.  
  36. // "=" assignment operator copies the specified tree into this tree.
  37. //
  38. template <class T>
  39. CmTBinaryTree<T>& CmTBinaryTree<T>::operator=(const CmTBinaryTree<T>& tr)
  40. {
  41.   if (&tr != this)
  42.   {
  43.     removeAll();
  44.     copy     (tr);
  45.     balance  ();
  46.   }
  47.   return *this;
  48. }
  49.  
  50.  
  51. // "add" adds a new item to the tree.
  52. //
  53. template <class T> Bool CmTBinaryTree<T>::add(const T& rObj)
  54. {
  55.   CmTBinaryTreeNode<T> *newnode = new CmTBinaryTreeNode<T>(rObj);
  56.   if (!newnode) return FALSE;
  57.  
  58.   if (!_root)                                // Tree is empty.  Add at root.
  59.     _root = newnode;
  60.  
  61.   else                                       // Tree is not empty.
  62.   {
  63.     CmTBinaryTreeNode<T> *parent = _root;
  64.     CmTBinaryTreeNode<T> *rover;
  65.     rover = (rObj < _root->_data) ? _root->_left : _root->_right;
  66.  
  67.     while (rover)                            // Search for vacant slot.
  68.     {
  69.       parent = rover;
  70.       rover  = (rObj < rover->_data) ? rover->_left : rover->_right;
  71.     }
  72.  
  73.     if (rObj < parent->_data) parent->_left  = newnode;  // Add new node.
  74.     else                      parent->_right = newnode;
  75.   }
  76.   _size++;
  77.   return TRUE;
  78. }
  79.  
  80.  
  81. // "remove" removes the specified item from the tree.
  82. //
  83. template <class T> Bool CmTBinaryTree<T>::remove(const T& rObj)
  84. {
  85.   if (!_root) return FALSE;                    // Exit if empty tree.
  86.  
  87.   CmTBinaryTreeNode<T> *rover  = _root;        // Init for search.
  88.   CmTBinaryTreeNode<T> *parent = NULL;
  89.   Bool                  done   = FALSE;
  90.  
  91.   while (rover && !done)                       // Search for item.
  92.   {
  93.     if (rObj != rover->_data)                  // Advance to next node.
  94.     {
  95.       parent = rover;
  96.       rover  = (rObj < rover->_data) ? rover->_left : rover->_right;
  97.     }
  98.  
  99.     else                                       // Item was found.
  100.     {
  101.       CmTBinaryTreeNode<T> *temp1 = rover;     // Save pointer to object.
  102.  
  103.       if (rover->_right == NULL)
  104.         rover = rover->_left;
  105.  
  106.       else if (rover->_right->_left == NULL)
  107.       {
  108.         rover        = rover->_right;
  109.         rover->_left = temp1->_left;
  110.       }
  111.  
  112.       else
  113.       {
  114.         CmTBinaryTreeNode<T> *temp2 = rover->_right;
  115.         while (temp2->_left->_left) temp2 = temp2->_left;
  116.         rover         = temp2->_left;
  117.         temp2->_left  = rover->_right;
  118.         rover->_left  = temp1->_left;
  119.         rover->_right = temp1->_right;
  120.       }
  121.  
  122.       if (!parent)                             // Object to remove is root.
  123.         _root = rover;
  124.  
  125.       else
  126.       {
  127.         if (temp1->_data < parent->_data) parent->_left  = rover;
  128.         else                              parent->_right = rover;
  129.       }
  130.  
  131.       delete temp1;
  132.       _size--;
  133.       done = TRUE;
  134.     }
  135.   }
  136.   return done;
  137. }
  138.  
  139.  
  140. // "lookup" returns the item in the tree equal to the specified item.
  141. //
  142. template <class T> const T& CmTBinaryTree<T>::lookup(const T& rObj) const
  143. {
  144.   if (!_root) return _error;
  145.  
  146.   CmTBinaryTreeNode<T> *rover = _root;
  147.   CmTBinaryTreeNode<T> *temp  = NULL;
  148.  
  149.   while (rover && !temp)
  150.   {
  151.     if (rObj == rover->_data)
  152.       temp  = rover;
  153.     else
  154.       rover = (rObj < rover->_data) ? rover->_left : rover->_right;
  155.   }
  156.   return (temp) ? temp->_data : _error;
  157. }
  158.  
  159.  
  160. // "contains" checks if the specified item is in this tree.
  161. //
  162. template <class T> Bool CmTBinaryTree<T>::contains(const T& rObj) const
  163. {
  164.   if (!_root) return NULL;
  165.  
  166.   CmTBinaryTreeNode<T> *rover = _root;
  167.   Bool                  found = FALSE;
  168.  
  169.   while (rover && !found)
  170.   {
  171.     if (rObj == rover->_data)
  172.       found = TRUE;
  173.     else
  174.       rover = (rObj < rover->_data) ? rover->_left : rover->_right;
  175.   }
  176.   return found;
  177. }
  178.  
  179.  
  180. // "removeAll" removes all items from this tree.
  181. //
  182. template <class T> void CmTBinaryTree<T>::removeAll()
  183. {
  184.   if (_root)
  185.   {
  186.     killNode(_root);
  187.     delete _root;
  188.     _root = NULL;
  189.     _size = 0;
  190.   }
  191. }
  192.  
  193.  
  194. // "occurrences" counts the occurrences of the specified item in this tree.
  195. //
  196. template <class T> unsigned CmTBinaryTree<T>::occurrences(const T& rObj) const
  197. {
  198.   unsigned                 occur = 0;
  199.   CmTBinaryTreeIterator<T> iterator(*this);
  200.   while (!iterator.done())
  201.     if (iterator.next() == rObj) occur++;
  202.   return occur;
  203. }
  204.  
  205.  
  206. // "root" returns the item at the root of this tree.
  207. //
  208. template <class T> const T& CmTBinaryTree<T>::root() const
  209. {
  210.   return (_root) ? _root->_data : _error;
  211. }
  212.  
  213.  
  214. // "balance" balances the current contents of the tree.
  215. //
  216. template <class T> void CmTBinaryTree<T>::balance()
  217. {
  218.   CmTQueue<CmTBinaryTreeNode<T>*> *que = new CmTQueue<CmTBinaryTreeNode<T>*>;
  219.   CmTBinaryTreeIterator<T> iterator(*this);
  220.   while (!iterator.done())
  221.   {
  222.     CmTBinaryTreeNode<T> *newnode = new CmTBinaryTreeNode<T>(iterator.next());
  223.     if (newnode) que->push(newnode);
  224.   }
  225.   removeAll();
  226.   balanceHalf(que, 0, que->size() - 1);
  227.   delete que;
  228. }
  229.  
  230.  
  231. // "newIterator" creates and returns a new tree iterator.
  232. //
  233. template <class T> CmTIterator<T>* CmTBinaryTree<T>::newIterator() const
  234. {
  235.   return new CmTBinaryTreeIterator<T>(*this);
  236. }
  237.  
  238.  
  239. // "balanceHalf" is called recursively for tree balancing.
  240. // 
  241. template <class T>
  242. void CmTBinaryTree<T>::balanceHalf(CmTQueue<CmTBinaryTreeNode<T>*> *que,
  243.                                    int low, int high)
  244. {
  245.   if (low <= high)
  246.   {
  247.     int mid = (low + high) / 2;
  248.     add(((*que)[mid])->_data);
  249.     balanceHalf(que, mid + 1, high);
  250.     balanceHalf(que, low, mid-1);
  251.   }
  252. }
  253.  
  254.  
  255. // "killNode" is recursively called to destroy branches of a node.
  256. //
  257. template <class T> void CmTBinaryTree<T>::killNode(CmTBinaryTreeNode<T>* sub)
  258. {
  259.   if (sub->_left)
  260.   {
  261.     killNode(sub->_left);
  262.     delete sub->_left;
  263.     sub->_left = NULL;
  264.   }
  265.  
  266.   if (sub->_right)
  267.   {
  268.     killNode(sub->_right);
  269.     delete sub->_right;
  270.     sub->_right = NULL;
  271.   }
  272. }
  273.  
  274.  
  275. // "CmTBinaryTreeIterator" is the iterator constructor.
  276. //
  277. template <class T>
  278. CmTBinaryTreeIterator<T>::CmTBinaryTreeIterator(const CmTBinaryTree<T>& tr)
  279.                                                 : _tree(tr)
  280. {
  281.   _stack = new CmTStack<CmTBinaryTreeNode<T>*>;
  282.   _node  = _tree._root;
  283.   if (_node)
  284.   {
  285.     while (_node->_left)
  286.     {
  287.       _stack->push(_node);
  288.       _node = _node->_left;
  289.     }
  290.   }
  291. }
  292.  
  293.  
  294. // "~CmTBinaryTreeIterator" is the iterator destructor.
  295. //
  296. template <class T> CmTBinaryTreeIterator<T>::~CmTBinaryTreeIterator()
  297. {
  298.   delete _stack;
  299. }
  300.  
  301.  
  302. // "done" returns TRUE if the iterator can proceed no further.
  303. //
  304. template <class T> Bool CmTBinaryTreeIterator<T>::done() const
  305. {
  306.   return (!_node);
  307. }
  308.  
  309.  
  310. // "next" returns the current item and advances the iterator.
  311. //
  312. template <class T> const T& CmTBinaryTreeIterator<T>::next()
  313. {
  314.   if (!_node) return _tree._error;                // Iteration is over.
  315.  
  316.   const T& retValue = _node->_data;               // Save item reference.
  317.  
  318.   if (_node->_right)                              // If there is a right
  319.   {                                               // branch, advance to it
  320.     _stack->push(_node);                          // and descend all the way
  321.     _node = _node->_right;                        // down it's left side.
  322.     while (_node->_left)
  323.     {
  324.       _stack->push(_node);
  325.       _node = _node->_left;
  326.     }
  327.   }
  328.  
  329.   else                                            // Otherwise, back up the
  330.   {                                               // tree until we are back
  331.     CmTBinaryTreeNode<T>* temp;                   // at the top or until we
  332.     do                                            // are no longer a right
  333.     {                                             // branch.
  334.       temp  = _node;
  335.       if (_stack->size() == 0) _node = NULL;
  336.       else                     _node = _stack->pop();
  337.     } while (_node && _node->_right == temp);
  338.   }
  339.   return retValue;
  340. }
  341.  
  342.  
  343. // "previous" returns the current item and advances the iterator.
  344. //
  345. template <class T> const T& CmTBinaryTreeIterator<T>::previous()
  346. {
  347.   if (!_node) return _tree._error;                // Iteration is over.
  348.  
  349.   const T& retValue = _node->_data;               // Save item reference.
  350.  
  351.   if (_node->_left)                               // If there is a left
  352.   {                                               // branch, advance to it
  353.     _stack->push(_node);                          // and descend all the way
  354.     _node = _node->_left;                         // down it's right side.
  355.     while (_node->_right)
  356.     {
  357.       _stack->push(_node);
  358.       _node = _node->_right;
  359.     }
  360.   }
  361.  
  362.   else                                            // Otherwise, back up the
  363.   {                                               // tree until we are back
  364.     CmTBinaryTreeNode<T>* temp;                   // at the top or until we
  365.     do                                            // are no longer a left
  366.     {                                             // branch.
  367.       temp  = _node;
  368.       if (_stack->size() == 0) _node = NULL;
  369.       else                     _node = _stack->pop();
  370.     } while (_node && _node->_left == temp);
  371.   }
  372.   return retValue;
  373. }
  374.  
  375.  
  376. // "current" returns the curren item.
  377. //
  378. template <class T> const T& CmTBinaryTreeIterator<T>::current() const
  379. {
  380.   return (_node) ? _node->_data : _tree._error;
  381. }
  382.  
  383.  
  384. // "first" moves the iterator to the first item.
  385. //
  386. template <class T> void CmTBinaryTreeIterator<T>::first()
  387. {
  388.   _stack->removeAll();
  389.   _node = _tree._root;
  390.   if (_node)
  391.   {
  392.     while (_node->_left)
  393.     {
  394.       _stack->push(_node);
  395.       _node = _node->_left;
  396.     }
  397.   }
  398. }
  399.  
  400.  
  401. // "last" moves the iterator to the last item.
  402. //
  403. template <class T> void CmTBinaryTreeIterator<T>::last()
  404. {
  405.   _stack->removeAll();
  406.   _node = _tree._root;
  407.   if (_node)
  408.   {
  409.     while (_node->_right)
  410.     {
  411.       _stack->push(_node);
  412.       _node = _node->_right;
  413.     }
  414.   }
  415. }
  416.